package lab1;

import java.rmi.Naming;
import java.io.*;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicLong;

import vs_a1.MessageServerInterface;

public class Server extends UnicastRemoteObject implements MessageServerInterface {


    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static AtomicLong runningID = new AtomicLong();
    private Queue<MessageData> deliveryQueue = new LinkedList<MessageData>();
    public Map<String, Long> clientMap = Collections.synchronizedMap(new HashMap<String, Long>());
    int queueLength;
    int holdTime;
    File file;
    FileWriter fw;
    PrintWriter pw;

    Server(int qL, int hT) throws RemoteException {
        super();
        this.queueLength = qL;
        this.holdTime = hT;
        Timestamp time = new Timestamp(System.currentTimeMillis());
        String log = "log_" + time;
        String log1 = log.substring(0, 17);
        String log2 = log.substring(18, 20);
        String log3 = log.substring(21, 23);
        log = log1 + "h" + log2 + "m" + log3 + "s";
        
        
        
        try{											//log erstellen
        	file = new File(log + ".txt");
        	fw = new FileWriter(file, true);

        	 
        	pw = new PrintWriter( fw );

        	 
        	 

        }catch(IOException e) {
        	 System.out.println("Logfile nicht erstellt");
        	 e.printStackTrace();
        }//catch
        
        try {
            LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            Naming.rebind("rmi://127.0.0.1:1099/MessageServer", this);
        }catch (RemoteException ex) {
            System.out.println(ex.getMessage());
        }catch (MalformedURLException e) {
            e.getMessage();
        }//catch
        System.out.println("Server running...");
    }//Server

    public void logFiller(String log){
    	
    	Timestamp time = new Timestamp(System.currentTimeMillis());
    	pw.println(time + log);
    	try{
    		fw.flush();
    		
    		pw.flush();
    	}catch (IOException e){
    		e.printStackTrace();
    		System.out.println("Konnte log nicht auffüllen");
    	}//catch
    }//logFiller
    
    
    @Override
    synchronized public void dropMessage(String clientID, String message) throws RemoteException {
    	logFiller(" Neue Nachricht von " + clientID + ": " + message);
    	Timestamp t = new Timestamp(System.currentTimeMillis());
        if (deliveryQueue.size() < queueLength) { // check for queue size and add to queue
            deliveryQueue.add(new MessageData(runningID.getAndIncrement(), clientID, message, t));
            System.out.println("Hier die Nachricht: " + message);
            System.out.println("Got Message from " + clientID);
        }else {
            // cleans up deliveryQueue with FIFO strategy and reinserts messages into queue
            System.out.println("cleaning up...");
            MessageData[] tmp = (MessageData[]) deliveryQueue.toArray(new MessageData[0]);
            tmp[0] = null;
            deliveryQueue.clear();
            for (MessageData mD : tmp) {
                if (mD != null) {
                    deliveryQueue.add(mD);
                }//if
            }//for
            deliveryQueue.add(new MessageData(runningID.getAndIncrement(), clientID, message, new Timestamp(System
                    .currentTimeMillis())));
        }//else
        System.out.println("Queue Groesse"+deliveryQueue.size());
        synchronized (clientMap){
        	if (!clientMap.containsKey(clientID)) { // adds the client first time to queue so that he can get messages after
        		clientMap.put(clientID, t.getTime());
        		logFiller(" Neuer Client: " + clientID + " hinzugefügt.");
        	}//if
        }//synchronized
    }//dropMessage

    
    
    @Override
    synchronized public String getMessage(String clientID) throws RemoteException {
        String message = "";
        if (!deliveryQueue.isEmpty()) {
        	synchronized (clientMap){
        		if (clientMap.containsKey(clientID)) { // checks for client in clientMap
        			MessageData[] tmp = (MessageData[]) deliveryQueue.toArray(new MessageData[0]);
        			for (MessageData d : tmp) {
        				if ((d.timestamp.getTime() > clientMap.get(clientID)) && !d.clientid.equals(clientID)) {
        					//checks for messages the client didnt get already
        					message = d.messageid + " " + d.clientid + ":" + d.message + " " + d.timestamp;
        					logFiller(" GetMessage Anfrage von Client " + clientID + ". Ausgegebene Nachricht: " + message);
        					clientMap.put(clientID, d.timestamp.getTime()); // update clientMap
        					break;
        				}//if
        			}//for
        			if (message == "") {
        				clientMap.put(clientID, System.currentTimeMillis());
        				logFiller(" Keine weiteren Nachrichten für den Client " + clientID + " bei Anfrage per getMessage");
        				 throw new RemoteException("no more messages");
        			}//if
        		}//if
        	}//synchronized
        }else {
        	logFiller(" Anfrage auf Messages bei leerer Queue");
             throw new RemoteException("no more messages");
        }//else
        return message;
    }
}